package com.ssy.lingxi.message.websocket.session;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.socket.WebSocketSession;

import java.io.Serializable;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * websocket session key
 * @author yzc
 * @version 2.0.0
 * @date 2021/7/8
 */
@Getter
@Setter
@EqualsAndHashCode
public class WsSessionKey implements Serializable {

    private static final long serialVersionUID = 8185381095583896355L;
    /**
     * 会员来源
     */
    private String source;
    /**
     * 会员id
     */
    private String memberId;
    /**
     * 角色id
     */
    private String roleId;
    /**
     * 用户id
     */
    private String userId;
    /**
     * sessionid
     */
    private String sessionId;

    /**
     * key的分割符
     */
    private static final String colon = ":";
    /**
     * key的任意匹配符
     */
    private static final String star = "*";

    public WsSessionKey(String source, String memberId, String roleId, String userId, String sessionId) {
        if (StringUtils.isEmpty(source)
                || StringUtils.isEmpty(memberId)
                || StringUtils.isEmpty(roleId)
                || StringUtils.isEmpty(userId)
                || StringUtils.isEmpty(sessionId)) {
            throw new IllegalArgumentException("source, memberId, roleId, sessionId, one of them is empty");
        }

        this.source = source;
        this.memberId = memberId;
        this.roleId = roleId;
        this.userId = userId;
        this.sessionId = sessionId;
    }

    public static WsSessionKey generate(WebSocketSession session) {
        String source = (String) session.getAttributes().get(WsSessionAttr.SOURCE);
        String memberId = (String) session.getAttributes().get(WsSessionAttr.MEMBER_ID);
        String roleId = (String) session.getAttributes().get(WsSessionAttr.ROLE_ID);
        String userId = (String) session.getAttributes().get(WsSessionAttr.USER_ID);

        return new WsSessionKey(source, memberId, roleId, userId, session.getId());
    }

    public static WsSessionKey parse(String sessionKey) {
        if (StringUtils.isEmpty(sessionKey)) {
            return null;
        }

        String[] string = sessionKey.split(colon);
        return new WsSessionKey(string[0], string[1], string[2], string[3], string[4]);
    }

    /**
     * 根据key生成正则
     *
     * @param key
     * @returnn
     */
    public static String getPattern(String key) {
        if (StringUtils.isEmpty(key)) {
            return null;
        }

        String[] split = key.split(colon);
        if ((split.length < 4)) {
            return null;
        }

        int tailStarIndex = split.length;
        for (int i = split.length - 1; i >= 0; i--) {
            if (!star.equals(split[i])) {
                break;
            }
            tailStarIndex = i;
        }

        StringBuilder pattern = new StringBuilder();
        pattern.append("^");
        for (int i = 0; i < tailStarIndex; i++) {
            if (star.equals(split[i])) {
                pattern.append("[0-9]+:");
            } else {
                pattern.append(split[i]).append(colon);
            }
        }
        pattern.deleteCharAt(pattern.length() - 1);

        pattern.append("(.*)").append("$");

        return pattern.toString();
    }

    public static String buildByMemberIdAndRoleId(Long memberId, Long roleId) {
        return buildPatternKey(null, memberId, roleId, null);
    }

    public static String buildByMemberIdAndRoleIdAndUserId(Long memberId, Long roleId, Long userId) {
        return buildPatternKey(null, memberId, roleId, userId);
    }

    public static String buildBySource(Integer source) {
        return buildPatternKey(source, null, null, null);
    }

    public static String buildByRoleId(Long roleId) {
        return buildPatternKey(null, null, roleId, null);
    }

    public static String buildByUserId(Long userId) {
        return buildPatternKey(null, null, null, userId);
    }

    /**
     * source:memberId:roleId:userId
     * @param source
     * @param memberId
     * @param roleId
     * @param userId
     * @return
     */
    private static String buildPatternKey(Integer source, Long memberId, Long roleId, Long userId) {
        return Stream.of(source, memberId, roleId, userId).map(id -> Objects.isNull(id) ? star : id.toString()).collect(Collectors.joining(colon, "", ""));
    }

    @Override
    public String toString() {
        return String.join(colon, source, memberId, roleId, userId, sessionId);
    }

}
